package dao

import (
	"a-common/constant"
	dom "a-common/domain"
	"a-system/domain/entity"
	"a-system/domain/tree"
	"errors"
	"strconv"
	"strings"
	"sync"

	"xorm.io/builder"
)

var (
	sysDeptDaoTemp *SysDeptDao
	sysDeptDaoOnce sync.Once
)

type SysDeptDao struct{}

func NewSysDeptDao() *SysDeptDao {
	sysDeptDaoOnce.Do(func() {
		sysDeptDaoTemp = &SysDeptDao{}
	})
	return sysDeptDaoTemp
}

// List 列表
func (m *SysDeptDao) List(args *entity.SysDeptDto) (dom.PageVo, error) {
	// 构建查询条件
	query := pgCli.Table(&entity.SysDept{}).Where("1 = 1")
	if args.DeptName != "" {
		query.And("dept_name = ?", args.DeptName)
	}
	if args.Status != "" {
		query.And("status = ?", args.Status)
	}
	// 分页
	if args.PageNum != 0 && args.PageSize != 0 {
		query.Limit(args.PageSize, (args.PageNum-1)*args.PageSize)
	}

	// 查询
	var vPage dom.PageVo
	var rows []entity.SysDeptPageVo
	total, err := query.Asc("dept_id").FindAndCount(&rows)
	if err != nil {
		return vPage, err
	}
	vPage.PageNum = args.PageNum
	vPage.PageSize = args.PageSize
	vPage.Rows = rows
	vPage.Total = total
	return vPage, err
}

// Get 查
func (m *SysDeptDao) Get(id string) (entity.SysDeptPageVo, error) {
	var v entity.SysDeptPageVo
	_, err := pgCli.Table(&entity.SysDept{}).ID(id).Get(&v)
	return v, err
}

// Add 增
func (m *SysDeptDao) Add(args *entity.SysDeptDto) (int64, error) {
	// 查询父节点的状态
	var v entity.SysDeptVo
	_, err := pgCli.Table(&entity.SysDept{}).ID(args.ParentId).Get(&v)
	if err != nil || v.Status == constant.DEPT_DISABLE {
		return 0, errors.New("部门停用，不允许新增")
	}
	args.Ancestors = v.Ancestors + "," + strconv.FormatInt(args.ParentId, 10)
	return pgCli.InsertOne(
		&entity.SysDept{
			ParentId:  args.ParentId,
			Ancestors: args.Ancestors,
			DeptName:  args.DeptName,
			OrderNum:  args.OrderNum,
			Leader:    args.Leader,
			Phone:     args.Phone,
			Email:     args.Email,
			Status:    args.Status,
			BaseStruct: dom.BaseStruct{
				CreatedBy: args.CreatedBy,
				UpdatedBy: args.CreatedBy,
				Remark:    args.Remark,
			},
		})
}

// Edit 改
func (m *SysDeptDao) Edit(args *entity.SysDeptDto) (int64, error) {
	return pgCli.ID(args.DeptId).Update(
		&entity.SysDept{
			ParentId: args.ParentId,
			// Ancestors:    args.Ancestors,
			DeptName: args.DeptName,
			OrderNum: args.OrderNum,
			Leader:   args.Leader,
			Phone:    args.Phone,
			Email:    args.Email,
			Status:   args.Status,
			BaseStruct: dom.BaseStruct{
				UpdatedBy: args.UpdatedBy,
				Remark:    args.Remark,
			},
		})
}

// Del 删
func (m *SysDeptDao) Del(ids string) (int64, error) {
	return pgCli.In("dept_id", strings.Split(ids, `,`)).Unscoped().Delete(&entity.SysDept{})
}

// GetDeptIdsByRoleId 查找部门ID
func (m *SysDeptDao) GetDeptIdsByRoleId(roleId int64, deptCheckStrictly bool) ([]int64, error) {
	query := pgCli.Table(&entity.SysDept{}).Cols("sys_dept.dept_id").Join(
		"left",
		"sys_role_dept",
		"sys_role_dept.dept_id = sys_dept.dept_id").Where("sys_role_dept.role_id = ?", roleId)
	if deptCheckStrictly {
		query.NotIn("sys_dept.dept_id", builder.Select("parent_id").From("sys_dept").Join(
			"inner",
			"sys_role_dept",
			"sys_role_dept.dept_id = sys_dept.dept_id").And(builder.Eq{"sys_role_dept.role_id": roleId}))
	}

	var deptIds []int64
	_, err := query.Asc("parent_id").Asc("order_num").Asc("dept_id").FindAndCount(&deptIds)
	return deptIds, err
}

// GetTree 获取部门树
func (m *SysDeptDao) GetTree() ([]*tree.TreeNode, error) {
	var v []*tree.DeptTreeDto
	err := pgCli.Find(&v)
	// 构建树
	return tree.GetDeptTree(v), err
}

// GetRelatedDepartmentIds 获取指定部门ID下的所有部门ID
func (m *SysDeptDao) GetRelatedDepartmentIds(departmentId int64) ([]int64, error) {
	// 定义部门ID切片，用于存储所有子部门ID
	departmentIds := make([]int64, 0)

	// 查找关联部门
	departments := make([]*int64, 0)
	err := pgCli.Table("sys_dept").Cols("dept_id").Where("parent_id = ?", departmentId).Find(&departments)
	if err != nil {
		return nil, err
	}

	// 将当前部门ID添加到切片中
	departmentIds = append(departmentIds, departmentId)

	// 遍历关联部门，递归获取所有子部门ID
	for _, dep := range departments {
		childIDs, err := m.GetRelatedDepartmentIds(*dep)
		if err != nil {
			return nil, err
		}
		departmentIds = append(departmentIds, childIDs...)
	}

	return departmentIds, nil
}
